import { type } from 'os';
(function () {
  // ! 索引类型(索引签名类型、索引类型查询与索引类型访问。)



  //#索引签名类型
  //索引签名类型主要指的是在接口或类型别名中，通过以下语法来快速声明一个键值类型一致的类型结构：
  interface AllStringTypes0 {
    [key: string]: string
  }
  type AllStringTypes1 = {
    [key: string]: string;
  }

  // 这时，即使你还没声明具体的属性，对于这些类型结构的属性访问也将全部被视为 string 类型：
  interface AllStringTypes {
    [key: string]: string;
  }

  type PropType1 = AllStringTypes['linbudu'];
  type PropType2 = AllStringTypes['599']
  type PropType3 = AllStringTypes[string]
  //在这个例子中我们声明的键的类型为 string（[key: string]），这也意味着在实现这个类型结构的变量中只能声明字符串类型的键：
  const foo: AllStringTypes = {
    'lys': '599'
  }
  const foo1: AllStringTypes = {
    'lys': '599',
    599: 'lys',
    [Symbol('ddd')]: 'symbol'
  }


  //索引签名类型也可以和具体的键值对类型声明并存，但这时这些具体的键值类型也需要符合索引签名类型的声明：
  interface AllStringTypes2 {
    //类型“number”的属性“propA”不能赋给“string”索引类型“boolean”。
    // propA: number;
    [key: string]: boolean;
    [key: symbol]: number;
  }


  interface StringOrBooleanTypes {
    propA: number;
    propB: boolean;
    [key: string]: number | boolean;
  }

  interface AnyTypeHere {
    [key: string]: any;
  }

  const foo2: AnyTypeHere['lys'] = 'any value'


  //#索引类型查询
  // keyof 操作符。严谨地说，它可以将对象中的所有键转换为对应字面量类型，然后再组合成联合类型。注意，这里并不会将数字类型的键名转换为字符串类型字面量，而是仍然保持为数字类型字面量。( keyof 的产物必定是一个联合类型。)

  interface anyInterface1 {
    [key: number]: string;
    [key: string]: any;
  }
  type keyType1 = keyof anyInterface1

  // const ky: keyType1 = true //不能将类型“boolean”分配给类型“keyof anyInterface1”。
  const ky1: keyType1 = 123
  const ky2: keyType1 = "true"

  interface Foo_1 {
    lys: 1;
    599: 2;
  }
  type Foo_11 = {
    lys: 1;
    599: 2;
  }

  type FooKeys = keyof Foo_1 // "linbudu" | 599
  type FooKeys_11 = keyof Foo_11 // "linbudu" | 599

  const num1: FooKeys = 599
  const num2: FooKeys_11 = 'lys'

  //它会由所有可用作对象键值的类型组成：string | number | symbol。也就是说，它是由无数字面量类型组成的，由此我们可以知道， keyof 的产物必定是一个联合类型。
  type anyUnion = keyof any;

  // #索引类型访问
  interface NumberRecord {
    [key: string]: number;

  }
  type PropType = NumberRecord[string]  // number

  interface Foo_2 {
    propA: number;
    propB: boolean;
  }

  type PropAType = Foo_2['propA']; // number
  type PropBType = Foo_2['propB']; // boolean
  //看起来这里就是普通的值访问，但实际上这里的'propA'和'propB'都是字符串字面量类型，而不是一个 JavaScript 字符串值。索引类型查询的本质其实就是，通过键的字面量类型（'propA'）访问这个键对应的键值类型（number）。

  //上面的 keyof 操作符能一次性获取这个对象所有的键的字面量类型，是否能用在这里？当然，这可是 TypeScript 啊。
  interface Foo_3 {
    propA: number;
    propB: boolean;
    propC: string;
  }

  type PropTypeUnion = Foo_3[keyof Foo_3] // string | number | boolean

  //注意，在未声明索引签名类型的情况下，我们不能使用 NumberRecord[string] 这种原始类型的访问方式，而只能通过键名的字面量类型来进行访问。
  interface Foo_4 {

    propA: number;
  }
  // 类型“Foo”没有匹配的类型“string”的索引签名。
  // type PropAType = Foo_4[string]

}())